home *** CD-ROM | disk | FTP | other *** search
- /**********************************************************************/
- /* raycyl.c */
- /* */
- /* Ray / cylinder intersection routines */
- /* Modified from Optik v(1.2e) (C) 1987 John Amanatides & Andrew Woo */
- /* */
- /* Copyright (C) 1992, Bernard Kwok */
- /* All rights reserved. */
- /* Revision 1.0 */
- /* May, 1992 */
- /**********************************************************************/
- #include <stdio.h>
- #include <math.h>
- #include "geo.h"
- #include "misc.h"
- #include "struct.h"
- #include "ray.h"
- #include "io.h"
-
- /**********************************************************************/
- extern OptionType Option;
- extern RayStats_Type RayStats;
-
- /**********************************************************************/
- /* Intersect a ray with a unit cylinder. Return any hit */
- /**********************************************************************/
- void RayCylinder(ray, hit, optr)
- register Ray *ray;
- register HitData *hit;
- register Objectt *optr;
- {
- double a,b,c,r1,r2,t,discrim,x,y,z;
-
- RayStats.rayCylinder++;
- if (Option.debug)
- printf("\t\tRay-Cylinder: (%g,%g,%g) > (%g,%g,%g)\n",
- ray->origin.x, ray->origin.y, ray->origin.z,
- ray->dir.x, ray->dir.y, ray->dir.z);
-
- /* find a,b,c of at**2 +bt +c */
- a= ray->dir.x*ray->dir.x + ray->dir.y*ray->dir.y;
- b= 2.0 * (ray->origin.x * ray->dir.x + ray->origin.y * ray->dir.y);
- c= ray->origin.x * ray->origin.x + ray->origin.y * ray->origin.y - 1.0;
-
- /* Calculate discriminant */
- discrim= b*b - 4.*a*c;
- if (discrim > 0.0) {
- /* find closest intersection (also watch for stability) */
- if (b < 0.0) {
- r2= (-b + sqrt(discrim)) / (2.0 * a);
- r1= c / (a * r2);
- } else {
- r1= (-b - sqrt(discrim)) / (2.0 * a);
- r2= c / (a * r1);
- }
- if (r1 <= MIN_DISTANCE) /* for round-off errors */
- t= r2;
- else t= r1;
-
- /* Store intersection info */
- if ((t > MIN_DISTANCE) && (t < hit->distance)) {
- z = ray->origin.z + t * ray->dir.z;
- if (z > -1.0 && z < 1.0) {
- x = ray->origin.x + t * ray->dir.x;
- y = ray->origin.y + t * ray->dir.y;
- RayStats.intCylinder++;
- Store_HitInter(hit, optr, t, x, y, z);
- if (!ray->shadow) {
- Store_HitNorm(hit, x, y, 0.0);
- hit->texture= hit->intersect;
- }
- }
- }
- }
-
- /* Check the two disks of the cylinder */
- if (ray->dir.z < -DAMN_SMALL || ray->dir.z > DAMN_SMALL) {
- /* check top disk */
- t= (1.0 - ray->origin.z) / ray->dir.z;
- if (t > MIN_DISTANCE && t < hit->distance) {
- x= ray->origin.x + t*ray->dir.x;
- y= ray->origin.y + t*ray->dir.y;
- /* within circle, store hit */
- if (x*x + y*y < 1.0) {
- RayStats.intCylinder++;
- Store_HitInter(hit, optr, t, x, y, 1.0);
- if (!ray->shadow) {
- Store_HitNorm(hit, 0.0, 0.0, 1.0);
- hit->texture= hit->intersect;
- }
- }
- }
-
- /* check bottom disk */
- t= (-1.-ray->origin.z)/ray->dir.z;
- if (t > MIN_DISTANCE && t < hit->distance) {
- x= ray->origin.x + t*ray->dir.x;
- y= ray->origin.y + t*ray->dir.y;
- if (x*x + y*y < 1.) {
- RayStats.intCylinder++;
- Store_HitInter(hit, optr, t, x, y, -1.);
- if (!ray->shadow) {
- Store_HitNorm(hit, 0., 0., -1.);
- }
- }
- }
- }
- }
-